﻿using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
using wwl.Contract.Dtos.Common; // 包含分页请求(PagedRequest)和分页结果(PagedResult)DTO
using System.Linq.Dynamic.Core; // 提供动态LINQ支持（如字符串排序、动态查询）
using wwl.Domain.Entities.Common; // 包含基础实体类BaseEntity

namespace wwl.DataAccess.Extensions
{
  /// <summary>
  /// IQueryable扩展方法类，封装查询相关的通用操作（分页、排序、过滤、关联查询等）
  /// 用于简化EF Core查询逻辑，提高代码复用性
  /// </summary>
  public static class QueryableExtensions
  {
    /// <summary>
    /// 对查询结果应用分页逻辑（跳过指定数量的记录，获取当前页数据）
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <param name="query">原始查询</param>
    /// <param name="request">分页请求参数（包含页码、页大小）</param>
    /// <returns>应用分页后的查询</returns>
    public static IQueryable<T> ToPaged<T>(this IQueryable<T> query, PagedRequest request)
    {
      // 计算需要跳过的记录数：(当前页码-1) * 每页大小
      // 然后获取指定数量的记录（页大小）
      return query.Skip((request.PageIndex - 1) * request.PageSize)
                 .Take(request.PageSize);
    }

    /// <summary>
    /// 对查询结果应用排序逻辑（支持动态排序字段和方向）
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <param name="query">原始查询</param>
    /// <param name="request">分页请求参数（包含排序字段SortBy、是否降序SortDesc）</param>
    /// <returns>应用排序后的查询</returns>
    public static IQueryable<T> ApplySorting<T>(this IQueryable<T> query, PagedRequest request)
    {
      // 如果未指定排序字段，则返回原始查询（不排序）
      if (string.IsNullOrWhiteSpace(request.SortBy))
        return query;

      // 确定排序方向（升序ASC/降序DESC）
      var orderDirection = request.SortDesc ? "DESC" : "ASC";
      // 使用动态LINQ的OrderBy方法，通过字符串拼接排序表达式（如"CreateTime DESC"）
      return query.OrderBy($"{request.SortBy} {orderDirection}");
    }

    /// <summary>
    /// 动态选择实体的指定字段（投影到动态类型）
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <param name="query">原始查询</param>
    /// <param name="fields">需要选择的字段，多个字段用逗号分隔（如"Id,Name,CreateTime"）</param>
    /// <returns>只包含指定字段的动态类型查询</returns>
    public static IQueryable<dynamic> SelectFields<T>(this IQueryable<T> query, string? fields)
    {
      // 如果未指定字段，则返回整个实体的动态类型转换
      if (string.IsNullOrWhiteSpace(fields))
        return query.Cast<dynamic>();

      // 使用动态LINQ的Select方法，通过字符串指定投影字段（如"new(Id, Name)"）
      // 最后转换为dynamic类型便于灵活访问字段
      return query.Select($"new({fields})").Cast<dynamic>();
    }

    /// <summary>
    /// 为查询添加关联属性包含（Eager Loading），用于加载导航属性
    /// </summary>
    /// <typeparam name="T">实体类型，必须继承自BaseEntity</typeparam>
    /// <param name="query">原始查询</param>
    /// <param name="includeProperties">需要包含的导航属性，多个属性用逗号分隔（如"User,OrderDetails"）</param>
    /// <returns>包含指定关联属性的查询</returns>
    public static IQueryable<T> IncludeProperties<T>(this IQueryable<T> query, string? includeProperties) where T : BaseEntity
    {
      // 如果未指定关联属性，则返回原始查询
      if (string.IsNullOrWhiteSpace(includeProperties))
        return query;

      // 拆分属性字符串为数组（处理逗号分隔的多个属性）
      var properties = includeProperties.Split(',', StringSplitOptions.RemoveEmptyEntries);
      // 遍历每个属性，调用EF的Include方法加载关联数据
      foreach (var property in properties)
      {
        query = query.Include(property.Trim()); // 去除空格，避免无效属性
      }

      return query;
    }

    /// <summary>
    /// 为查询应用过滤条件（谓词表达式）
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <param name="query">原始查询</param>
    /// <param name="filter">过滤条件表达式（如x => x.Status == 1），可为null（表示不过滤）</param>
    /// <returns>应用过滤后的查询</returns>
    public static IQueryable<T> ApplyFilter<T>(this IQueryable<T> query, Expression<Func<T, bool>>? filter)
    {
      // 如果过滤条件为null，返回原始查询；否则应用Where过滤
      return filter == null ? query : query.Where(filter);
    }

    /// <summary>
    /// 构建完整的查询逻辑（依次应用过滤、排序、关联属性包含）
    /// 是查询组装的核心方法，按固定顺序处理查询条件
    /// </summary>
    /// <typeparam name="T">实体类型，必须继承自BaseEntity</typeparam>
    /// <param name="query">原始查询</param>
    /// <param name="request">分页请求参数（包含排序、关联属性等信息）</param>
    /// <param name="filter">可选的过滤条件表达式</param>
    /// <returns>组装完成的查询（包含过滤、排序、关联属性）</returns>
    public static IQueryable<T> BuildQuery<T>(this IQueryable<T> query, PagedRequest request,
        Expression<Func<T, bool>>? filter = null) where T : BaseEntity
    {
      // 1. 应用过滤条件
      query = query.ApplyFilter(filter);
      // 2. 应用排序
      query = query.ApplySorting(request);
      // 3. 包含关联属性
      query = query.IncludeProperties(request.IncludeProperties);
      return query;
    }

    /// <summary>
    /// 将查询转换为分页结果对象（包含数据列表、总记录数等分页信息）
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <param name="query">已组装好的查询（包含过滤、排序等，未分页）</param>
    /// <param name="request">分页请求参数</param>
    /// <param name="cancellationToken">取消令牌，用于终止异步操作</param>
    /// <returns>分页结果对象</returns>
    public static async Task<wwl.Contract.Dtos.Common.PagedResult<T>> ToPagedResultAsync<T>(
            this IQueryable<T> query,
            PagedRequest request,
            CancellationToken cancellationToken = default)
    {
      // 1. 查询满足条件的总记录数（用于计算总页数）
      var totalCount = await query.CountAsync(cancellationToken);
      // 2. 应用分页并获取当前页数据列表
      var items = await query.ToPaged(request).ToListAsync(cancellationToken);

      // 3. 构建并返回分页结果对象
      return new wwl.Contract.Dtos.Common.PagedResult<T>
      {
        Items = items,       // 当前页的数据列表
        TotalCount = totalCount, // 总记录数
        PageIndex = request.PageIndex, // 当前页码
        PageSize = request.PageSize    // 每页大小
      };
    }
  }
}